﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureRoof.h"
#include "AlgorithmCurveOperate.h"
#include "AlgorithmMinimalDistance.h"
#include "AlgorithmProject.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "ICopyStrategyReporter.h"
#include "IDocument.h"
#include "IElementModelShape.h"
#include "IElementParameters.h"
#include "IElementParentReporter.h"
#include "IElementPosition.h"
#include "IElementStatus.h"
#include "IElementTransformationComponent.h"
#include "IExternalDataComponent.h"
#include "IFamily.h"
#include "IGenericElement.h"
#include "IGraphicsCurve3d.h"
#include "IInstance.h"
#include "IInstanceType.h"
#include "ILevel.h"
#include "IModelLine.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IPlane.h"
#include "IPositionAssociatedPlane.h"
#include "IPositionPoint2d.h"
#include "IRegenerator.h"
#include "IStructureSlopeLine.h"
#include "LevelUtils.h"
#include "RoofCustomData.h"
#include "StructureInstanceLevelUtils.h"
#include "StructureRoofInput.h"
#include "StructureRoofProfileUsedModelLineUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

DEFINE_STRUCTURE_INSTANCE_METHODS(StructureRoof)

DBOBJECT_DATA_DEFINE(StructureRoof)
{
    m_pOwnerElement = nullptr;
    SetConcreteStrengthGrade__(ConcreteStrengthGradeType::CSG_C30);
}

StructureRoof* StructureRoof::Create(const StructureRoofInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstanceType* pInstanceType = quick_cast<IInstanceType>(pDoc->GetElement(pInput->InstanceTypeId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstanceType, L"pInstanceType为空",L"GDMPLab",L"2024-03-30");

    // ===========暂时把共享关了，后续需要完善HasSameValue函数=================
    IInstance* pInstance = pInstanceType->CreateInstance(L"屋顶实例", pInput->CanBeShared, pInput->CreationOption, pInput->IsCreateGeometryRelationshipComponent);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    
    IElementStatus* pStatus = pInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(pInput->Visible);

    ElementId instanceId = pInstance->GetElementId();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(instanceId.IsValid(), L"instanceId无效",L"GDMPLab",L"2024-03-30");

    // 注册外部数据
    StructureRoof* pRoof = StructureRoof::RegisterExternalData(pInstance);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pRoof, L"pRoof为空",L"GDMPLab",L"2024-03-30");
    pRoof->SetConcreteStrengthGrade(pInput->ConcreteType);

    // 轮廓信息
    std::vector<IModelLine*> profileCurves = pInput->ProfileCurves;
    std::vector<IStructureSlopeLine*> slopeLines = pInput->SlopeLines;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(profileCurves.size() > 0, L"传入的轮廓为空",L"GDMPLab",L"2024-03-30");

    // 更新轮廓信息
    bool bOk = pRoof->UpdateProfileCurvesAndSlopeLines(profileCurves, slopeLines);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"更新轮廓信息失败",L"GDMPLab",L"2024-03-30");

    // 计算轮廓包围盒中心点作为插入点，以便将轮廓位置变换到坐标原点
    std::vector<OwnerPtr<ICurve3d>> profileICurvesOwner;
    std::vector<const ICurve3d*> profileICurves;
    std::vector<OwnerPtr<ICurve3d>> outerCurves; // 外圈轮廓
    std::vector<int> outerIndexes;
    for (auto& pModelLine : profileCurves)
    {
        OwnerPtr<ICurve3d> opCurve3d = pModelLine->GetGeometryCurve();
        profileICurves.push_back(opCurve3d.get());
        profileICurvesOwner.push_back(TransferOwnership(opCurve3d));
    }
    gcmp::AlgorithmCurveOperate::CreateSequencedCurves(profileICurves, outerCurves, outerIndexes);

    Vector3d insertPt = Vector3d::Zero;
    std::vector<const ICurve3d*> curves;
    FOR_EACH(curve, outerCurves)
    {
        curves.push_back(curve.get());
    }

    Box3d box;
    FOR_EACH(pCurve, curves)
    {
        box.MergeBox(pCurve->GetBox());
    }

    insertPt = box.GetCenter();

    ElementId associatedPlaneId = pInput->AssociatedPlaneId;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(associatedPlaneId.IsValid(), L"associatedPlaneId无效",L"GDMPLab",L"2024-03-30");

    const ILevel* pStoreyLevel = nullptr;
    if (pInput->StoreyId.IsValid())
    {
        pStoreyLevel = LevelUtils::GetLevelById(pDoc, pInput->StoreyId);
    }
    else
    {
        pStoreyLevel = StructureInstanceLevelUtils::GetRoofStoreyLevelFromPositioningLevel(pDoc, associatedPlaneId);
    }
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStoreyLevel, L"pStoreyLevel为空",L"GDMPLab",L"2024-03-30");
    bOk = StructureInstanceLevelUtils::CreateInstanceStoreyLevel(pInstance, pStoreyLevel);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"创建屋顶的StoreyLevel失败",L"GDMPLab",L"2024-03-30");

    double associatedPlaneOffset = pInput->AssociatedPlaneOffset;

    // 以插入点为坐标系原点
    Coordinate3d baseCoord(insertPt, Vector3d::UnitX, Vector3d::UnitY);
    bOk = IElementPosition::CreatePoint2dOnTopAssociatedPlanePositionBehavior(pInstance, associatedPlaneId,
        baseCoord.GetOrigin(), baseCoord.GetX(), baseCoord.GetY());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(bOk, L"CreatePositionBehavior失败",L"GDMPLab",L"2024-03-30");
    IPositionAssociatedPlane::SetBottomPlaneHeightOffset(pInstance, associatedPlaneOffset);

    // 为模型线绑定实例对象
    StructureRoofProfileUsedModelLineUtils::SetAssociatedInstanceIdForModelLines(profileCurves, instanceId);

    // 将模型线和坡度线从世界坐标系转换到屋顶的局部坐标系
    const IElementPosition *posBehavior = pInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");
    Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
    bOk = mat.MakeInverse();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"变换矩阵求逆失败",L"GDMPLab",L"2024-03-30");
    bOk = pRoof->TransformSlopeLinesAndProfileCurvesCoordinateSystem(profileCurves, slopeLines, mat, instanceId, associatedPlaneOffset, true);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"坐标转换失败",L"GDMPLab",L"2024-03-30");

    // 数据分组
    std::map<IStructureSlopeLine*, IModelLine*> slopeLineAndProfileCurveMap;
    if (slopeLines.size() > 0)
    {
        bOk = pRoof->GenerateSlopeLineAndProfileCurveMap(slopeLines, profileCurves, slopeLineAndProfileCurveMap);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"数据分组失败",L"GDMPLab",L"2024-03-30");
    }

    // 生成屋顶自定义数据
    OwnerPtr<RoofCustomData> opRoofData = NEW_AS_OWNER_PTR(RoofCustomData);
    bOk = pRoof->GenerateRoofCustomData(opRoofData, profileCurves, slopeLineAndProfileCurveMap);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"生成屋顶自定义数据失败",L"GDMPLab",L"2024-03-30");
    opRoofData->SetOwnerElement(pInstance);

    // 设置自定义参数
    IElementParameters* pElementParam = pInstance->GetElementParameters();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementParam, L"pElementParam为空",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IParameter> param = pElementParam->GetParameterByUid(PARAMETER_UID(InputCustomDataBuiltInParameter));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(param), L"获取自定义参数失败",L"GDMPLab",L"2024-03-30");
    param->SetValueAsCustomData(TransferOwnership(opRoofData));
    bOk = pElementParam->SetParameter(param.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"SetParameter失败",L"GDMPLab",L"2024-03-30");

    bOk = pDoc->GetRegenerator()->RegenerateElement(instanceId);
    if (!bOk)
    {
        return nullptr;
    }
    
    return pRoof;
}

NdbObject* StructureRoof::GetTopOwnerObject() const
{
    return nullptr;
}

StructureRoof* StructureRoof::Edit(const StructureRoofEditInput* pInput)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInput, L"pInput为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pInput->Document;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    ElementId instanceId = pInput->InstanceId;
    IInstance *pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    const IElementPosition *posBehavior = pInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");

    const IPositionPoint2d *posPoint2d = quick_cast<const IPositionPoint2d>(posBehavior->GetPositionGeometry());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posPoint2d, L"posPoint2d为空",L"GDMPLab",L"2024-03-30");

    const IPositionAssociatedPlane *posAssociatedPlane = quick_cast<const IPositionAssociatedPlane>(posBehavior->GetPositionAssociatedPlane());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posAssociatedPlane, L"posAssociatedPlane为空",L"GDMPLab",L"2024-03-30");

    StructureRoof* pRoof = StructureRoof::Get(pInstance);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pRoof, L"pRoof为空",L"GDMPLab",L"2024-03-30");

    // 轮廓信息
    std::vector<IModelLine*> profileCurves = pInput->ProfileCurves;
    std::vector<IStructureSlopeLine*> slopeLines = pInput->SlopeLines;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(profileCurves.size() > 0, L"传入的轮廓为空",L"GDMPLab",L"2024-03-30");

    // 更新轮廓信息
    bool bOk = pRoof->UpdateProfileCurvesAndSlopeLines(profileCurves, slopeLines);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"更新轮廓信息失败",L"GDMPLab",L"2024-03-30");

    // 将模型线和坡度线从世界坐标系转换到屋顶的局部坐标系
    Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
    bOk = mat.MakeInverse();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"变换矩阵求逆失败",L"GDMPLab",L"2024-03-30");
    bOk = pRoof->TransformSlopeLinesAndProfileCurvesCoordinateSystem(profileCurves, slopeLines, mat, pInstance->GetElementId(), 0.0, false);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"坐标转换失败",L"GDMPLab",L"2024-03-30");

    // 数据分组
    std::map<IStructureSlopeLine*, IModelLine*> slopeLineAndProfileCurveMap;
    if (slopeLines.size() > 0)
    {
        bOk = pRoof->GenerateSlopeLineAndProfileCurveMap(slopeLines, profileCurves, slopeLineAndProfileCurveMap);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"数据分组失败",L"GDMPLab",L"2024-03-30");
    }

    // 生成屋顶自定义数据
    OwnerPtr<RoofCustomData> opRoofData = NEW_AS_OWNER_PTR(RoofCustomData);
    bOk = pRoof->GenerateRoofCustomData(opRoofData, profileCurves, slopeLineAndProfileCurveMap);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"生成屋顶自定义数据失败",L"GDMPLab",L"2024-03-30");

    // 设置自定义参数
    IElementParameters* pElementParam = pInstance->GetElementParameters();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementParam, L"pElementParam为空",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IParameter> param = pElementParam->GetParameterByUid(PARAMETER_UID(InputCustomDataBuiltInParameter));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(IParameter::IsValidParameter(param), L"获取自定义参数失败",L"GDMPLab",L"2024-03-30");
    param->SetValueAsCustomData(TransferOwnership(opRoofData));
    bOk = pElementParam->SetParameter(param.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(bOk, L"SetParameter失败",L"GDMPLab",L"2024-03-30");

    // 生成形体

    IElementStatus* pStatus = pInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(true);
    bOk = pDoc->GetRegenerator()->RegenerateElement(instanceId);
    if (!bOk)
    {
        return nullptr;
    }

    return pRoof;
}

StructureRoof* StructureRoof::Get(IInstance* pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        IExternalData* pData = pExternalDataComponent->FindExternalData(StructureRoof::GetStaticClassSchema()->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");

        return quick_cast<StructureRoof>(pData);
    }
    return nullptr;
}

const StructureRoof* StructureRoof::Get(const IInstance* pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    if (const IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        const IExternalData* pData = pExternalDataComponent->FindExternalData(StructureRoof::GetStaticClassSchema()->GetName());
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");

        return quick_cast<const StructureRoof>(pData);
    }
    return nullptr;
}

void StructureRoof::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
    FOR_EACH(id, deletedElementIds)
    {
        auto it = std::find(GetProfileCurveIds().begin(), GetProfileCurveIds().end(), id);
        if (it != GetProfileCurveIds().end())
        {
            GetProfileCurveIds().erase(it);
        }
        else
        {
            auto it = std::find(GetSlopeLineIds().begin(), GetSlopeLineIds().end(), id);
            if (it != GetSlopeLineIds().end())
            {
                GetSlopeLineIds().erase(it);
            }
        }
    }
}

void StructureRoof::ReportParents(IElementParentReporter& reporter) const
{
    FOR_EACH(id, GetProfileCurveIds())
    {
        reporter.ReportWeak(id);
    }
    FOR_EACH(id, GetSlopeLineIds())
    {
        reporter.ReportWeak(id);
    }
}

void StructureRoof::GetCalculators(ICalculatorCollection * calculators) const
{
}

void StructureRoof::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    pParamDefIds->push_back(PARAMETER_ID(ConcreteStrengthGradeBuiltInParameter));
}

OwnerPtr<IParameter> StructureRoof::GetNativeParameter(int paramDefId) const
{
    OwnerPtr<IParameter> param;
    if (paramDefId == PARAMETER_ID(ConcreteStrengthGradeBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Int, false, false,
            //true, PARAMETER_UID(ConcreteStrengthGradeBuiltInParameter), ParameterProcessType::GeneralInput);
        ParameterAttributes pa = {false, false, true};
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Int, pa, 
            PARAMETER_UID(ConcreteStrengthGradeBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsInt((int)GetConcreteStrengthGrade__());
        return TransferOwnership(param);
    }
    return nullptr;
}

bool StructureRoof::SetNativeParameter(const IParameter *param, std::wstring* errorMsg)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (param->GetParameterDefinitionId() == PARAMETER_ID(ConcreteStrengthGradeBuiltInParameter))
    {
        SetConcreteStrengthGrade((ConcreteStrengthGradeType)param->GetValueAsInt());
        return true;
    }
    return false;
}

bool StructureRoof::IsParameterModifiable(int paramDefId) const
{
    return false;
}

void StructureRoof::Report(const ICopyContext & copyContext, ICopyStrategyReporter& reporter) const
{
    reporter.ReportToCopy(GetOwnerElementId());

    FOR_EACH(id, GetProfileCurveIds())
    {
        reporter.ReportToCopy(id);
    }
    FOR_EACH(id, GetSlopeLineIds())
    {
        reporter.ReportToCopy(id);
    }
}

IDocument* StructureRoof::GetDocument() const
{
    return m_pOwnerElement ? m_pOwnerElement->GetDocument() : nullptr;
}

ElementId StructureRoof::GetOwnerElementId() const
{
    return m_pOwnerElement ? m_pOwnerElement->GetElementId() : ElementId::InvalidID;
}

StructureRoof* StructureRoof::RegisterExternalData(IInstance* pInstance)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pInstance, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<StructureRoof> opRoof = NEW_AS_OWNER_PTR(StructureRoof);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opRoof, L"opRoof为空",L"GDMPLab",L"2024-03-30");
    opRoof->SetOwnerElement(pInstance);

    StructureRoof* pRoof = opRoof.get();
    if (IExternalDataComponent * pExternalDataComponent = pInstance->GetExternalDataComponent())
    {
        pExternalDataComponent->RegisterExternalData(StructureRoof::GetStaticClassSchema()->GetName(), TransferOwnership(opRoof));
    }
    return pRoof;
}

bool StructureRoof::UpdateProfileCurvesAndSlopeLines(const std::vector<IModelLine*> profileCurves, const std::vector<IStructureSlopeLine*> slopeLines)
{
    std::vector<ElementId> profileCurveIds;
    FOR_EACH(pModelLine, profileCurves)
    {
        profileCurveIds.push_back(pModelLine->GetOwnerElement()->GetElementId());
    }
    this->SetProfileCurveIds(profileCurveIds);

    std::vector<ElementId> slopeLineIds;
    FOR_EACH(pSlopeLine, slopeLines)
    {
        slopeLineIds.push_back(pSlopeLine->GetOwnerElement()->GetElementId());
    }
    this->SetSlopeLineIds(slopeLineIds);

    return true;
}

bool StructureRoof::GenerateSlopeLineAndProfileCurveMap(
    std::vector<IStructureSlopeLine*>& slopeLines,
    std::vector<IModelLine*>& profileCurves,
    std::map<IStructureSlopeLine*, IModelLine*>& slopeLineAndProfileCurveMap)
{
    size_t count = profileCurves.size();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(count > 0, L"传入的轮廓为空",L"GDMPLab",L"2024-03-30");

    for (int i = 0; i < slopeLines.size(); i++)
    {
        // 判断坡度线的起点是否在某轮廓线上
        bool isSlopeLineStartPointOnProfileCurve = false;
        Vector3d startPt = slopeLines[i]->GetStart();

        for (int j = 0; j < profileCurves.size(); j++)
        {
            Vector3d minimalDistancePointOnCurve;
            double pParamOnCurve;
            double minimalDistance;
            AlgorithmMinimalDistance::Calculate(profileCurves[j]->GetGeometryCurve().get(), startPt, minimalDistancePointOnCurve, true, &pParamOnCurve, minimalDistance);
            if (minimalDistance + Constants::DOUBLE_EPS < gcmp::Constants::LENGTH_EPS)
            {
                slopeLineAndProfileCurveMap.insert(std::pair<IStructureSlopeLine*, IModelLine*>(slopeLines[i], profileCurves[j]));
                profileCurves.erase(profileCurves.begin() + j);
                isSlopeLineStartPointOnProfileCurve = true;
                break;
            }
        }

        if (!isSlopeLineStartPointOnProfileCurve)
        {
            DBG_WARN(L"坡度线位置不正确：坡度线的起点必须在轮廓线上！",L"GDMPLab",L"2024-03-30");
        }
    }

    if (slopeLineAndProfileCurveMap.size() + profileCurves.size() != count)
    {
        DBG_WARN(L"数据分组出错",L"GDMPLab",L"2024-03-30");
    }

    return true;
}

bool StructureRoof::TransformSlopeLinesAndProfileCurvesCoordinateSystem(std::vector<IModelLine*> profileCurves, std::vector<IStructureSlopeLine*> slopeLines,
    const Matrix4d& transformMatrix, const ElementId instanceId, const double associatedPlaneOffset, bool isCreating)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(profileCurves.size() > 0, L"传入的轮廓为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(instanceId.IsValid(), L"instanceId无效",L"GDMPLab",L"2024-03-30");

    FOR_EACH(pModelLine, profileCurves)
    {
        IGenericElement* pGenericElement = quick_cast<IGenericElement> (pModelLine->GetOwnerElement());
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

        IElementPosition* pModelLineElementPosition = pGenericElement->GetElementPosition();
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelLineElementPosition, L"pModelLineElementPosition为空",L"GDMPLab",L"2024-03-30");

        if (isCreating)
        {
            IPositionAssociatedPlane* pAssociatedPlane = pModelLineElementPosition->GetPositionAssociatedPlane();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pAssociatedPlane, L"pAssociatedPlane为空",L"GDMPLab",L"2024-03-30");

            pAssociatedPlane->SetBasePlaneOffset(associatedPlaneOffset);
        }
        pGenericElement->GetElementTransformationComponent()->Transform(transformMatrix);
    }

    if (slopeLines.size() > 0)
    {
        FOR_EACH(pSlopeLine, slopeLines)
        {
            pSlopeLine->SetInstanceId(instanceId);
            IGenericElement* pGenericElement = quick_cast<IGenericElement> (pSlopeLine->GetOwnerElement());
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

            IElementPosition* pSlopeLineElementPosition = pGenericElement->GetElementPosition();
            DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlopeLineElementPosition, L"pSlopeLineElementPosition为空",L"GDMPLab",L"2024-03-30");

            if (isCreating)
            {
                IPositionAssociatedPlane* pAssociatedPlane = pSlopeLineElementPosition->GetPositionAssociatedPlane();
                DBG_WARN_AND_RETURN_FALSE_UNLESS(pAssociatedPlane, L"pAssociatedPlane为空",L"GDMPLab",L"2024-03-30");

                pAssociatedPlane->SetBasePlaneOffset(associatedPlaneOffset);
            }
            pGenericElement->GetElementTransformationComponent()->Transform(transformMatrix);
        }
    }

    return true;
}

bool StructureRoof::GenerateRoofCustomData(OwnerPtr<RoofCustomData>& opRoofData, std::vector<IModelLine*>& profileCurves,
    std::map<IStructureSlopeLine*, IModelLine*>& slopeLineAndProfileCurveMap)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(profileCurves.size() + slopeLineAndProfileCurveMap.size() > 0, L"传入的轮廓信息有误",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IPlane> opPlane = IPlane::Create(Vector3d::Zero, Vector3d::UnitX, Vector3d::UnitY);

    for (auto it = slopeLineAndProfileCurveMap.begin(); it != slopeLineAndProfileCurveMap.end(); it++)
    {
        IStructureSlopeLine* pSlopeLine = it->first;
        IModelLine* pModelLine = it->second;

        // 设置SlopeLineData
        OwnerPtr<SlopeLineData> opSlopeLineData = NEW_AS_OWNER_PTR(SlopeLineData);
        OwnerPtr<ICurve2d> opSlopeCurve = AlgorithmProject::Project(pSlopeLine->GetSlopeLine().get(), opPlane.get());
        opSlopeLineData->SetSlopeLine(TransferOwnership(opSlopeCurve));
        double slopeAngle = pSlopeLine->GetSlopeAngle();  // 角度为弧度制
        opSlopeLineData->SetSlopeAngle(slopeAngle);

        // 设置ProfileCurveData
        OwnerPtr<ProfileCurveData> opProfileCurveData = NEW_AS_OWNER_PTR(ProfileCurveData);
        OwnerPtr<ICurve2d> opProfileCurve = AlgorithmProject::Project(pModelLine->GetGeometryCurve().get(), opPlane.get());
        opProfileCurveData->SetProfileCurve(TransferOwnership(opProfileCurve));
        opProfileCurveData->SetIsDefineSlope(false);      // 定义了坡度线，则轮廓线就不会定义坡度
        opProfileCurveData->SetSlopeLineData(TransferOwnership(opSlopeLineData));

        opRoofData->AddProfileCurveData(TransferOwnership(opProfileCurveData));

        pModelLine->GetOwnerElement()->GetStatus()->SetIsVisible(false);
        pSlopeLine->GetOwnerElement()->GetStatus()->SetIsVisible(false);
    }

    FOR_EACH(pModelLine, profileCurves)
    {
        OwnerPtr<ProfileCurveData> opProfileCurveData = NEW_AS_OWNER_PTR(ProfileCurveData);
        OwnerPtr<ICurve2d> opProfileCurve = AlgorithmProject::Project(pModelLine->GetGeometryCurve().get(), opPlane.get());
        opProfileCurveData->SetProfileCurve(TransferOwnership(opProfileCurve));

        IElementParameters* pElementParameters = pModelLine->GetOwnerElement()->GetElementParameters();
        OwnerPtr<IParameter> paramIsDefineSlope = pElementParameters->GetParameterByUid(PARAMETER_UID(RoofProfileCurveDefineSlopeBuiltInParameter));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(paramIsDefineSlope), L"paramIsDefineSlope参数无效",L"GDMPLab",L"2024-03-30");
        bool isDefineSlope = paramIsDefineSlope->GetValueAsBool();
        opProfileCurveData->SetIsDefineSlope(isDefineSlope);

        if (isDefineSlope)
        {
            OwnerPtr<IParameter> paramSlopeAngle = pElementParameters->GetParameterByUid(PARAMETER_UID(RoofProfileCurveSlopeAngleValueBuiltInParameter));
            DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(paramSlopeAngle), L"paramSlopeAngle参数无效",L"GDMPLab",L"2024-03-30");
            double slopeAngle = paramSlopeAngle->GetValueAsDouble();
            opProfileCurveData->SetSlopeAngle(slopeAngle);
        }

        OwnerPtr<IParameter> paramCurveOffset = pElementParameters->GetParameterByUid(PARAMETER_UID(RoofProfileCurveOffsetBuiltInParameter));
        DBG_WARN_AND_RETURN_FALSE_UNLESS(IParameter::IsValidParameter(paramCurveOffset), L"paramCurveOffset参数无效",L"GDMPLab",L"2024-03-30");
        double curveOffset = paramCurveOffset->GetValueAsDouble();
        opProfileCurveData->SetProfileCurveOffset(curveOffset);

        opProfileCurveData->SetSlopeLineData(nullptr);     // 此分组中的轮廓线没有定义坡度线

        opRoofData->AddProfileCurveData(TransferOwnership(opProfileCurveData));

        pModelLine->GetOwnerElement()->GetStatus()->SetIsVisible(false);
    }

    return true;
}
